package com.qiguliuxing.dts.service.base;

import com.github.pagehelper.PageHelper;
import com.qiguliuxing.dts.common.util.ResponseUtils;
import com.qiguliuxing.dts.db.bean.SeckillGoodsAllinone;
import com.qiguliuxing.dts.db.bean.SeckillGoodsVo;
import com.qiguliuxing.dts.db.dao.DtsGoodsMapper;
import com.qiguliuxing.dts.db.dao.DtsGoodsProductMapper;
import com.qiguliuxing.dts.db.dao.DtsSeckillGoodsMapper;
import com.qiguliuxing.dts.db.dao.ex.DtsSeckillGoodsMapperEx;
import com.qiguliuxing.dts.db.domain.*;
import com.qiguliuxing.dts.service.seckill.cache.SeckillCache;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

/**
 * 秒杀服务
 *
 * @author 1197673878@qq.com
 * @since 2020年10月13日 上午12:00:34
 */
@Service
public class DtsGoodsSeckillService {
    private static final Logger logger = LoggerFactory.getLogger(DtsGoodsSeckillService.class);

    @Resource
    private DtsSeckillGoodsMapperEx dtsSeckillGoodsMapperEx;
    @Resource
    private DtsSeckillGoodsMapper dtsSeckillGoodsMapper;
    @Resource
    private DtsGoodsMapper goodsMapper;
    @Resource
    private DtsGoodsProductMapper dtsGoodsProductMapper;

    @Autowired
    private DtsGoodsProductService productService;
    @Autowired
    private SeckillCache seckillCache;

    /**
     * 秒杀商品列表
     *
     * @param param 参数
     * @return 数据
     */
    public List<SeckillGoodsVo> querySeckillGoods(Map<String, Object> param) {
        int offset = (int) param.get("offset");
        int limit = (int) param.get("limit");
        PageHelper.startPage(offset, limit);
        return queryAllSeckillGoods(param);
    }

    /**
     * 秒杀商品列表
     *
     * @param param 参数
     * @return 数据
     */
    public List<SeckillGoodsVo> queryAllSeckillGoods(Map<String, Object> param) {
        return dtsSeckillGoodsMapperEx.selectSeckillGoods(param);
    }

    /**
     * 管理员后台查询秒杀商品列表
     *
     * @param param 参数
     * @return 数据
     */
    public List<SeckillGoodsVo> selectAllSeckillGoods(Map<String, Object> param) {
        int offset = (int) param.get("offset");
        int limit = (int) param.get("limit");
        PageHelper.startPage(offset, limit);
        return dtsSeckillGoodsMapperEx.selectAllSeckillGoods(param);
    }

    /**
     * 判断商品是否处于秒杀进行中
     *  先从db中获取秒杀商品配置，如果属于秒杀日期，且当前时间在对应商品配置的秒杀批次内，则认为处于秒杀进行中
     * @param seckillGoodsId
     * @return
     */
    public boolean seckillDoing(int seckillGoodsId) {
        DtsSeckillGoods seckillGoods = dtsSeckillGoodsMapper.selectByPrimaryKey(seckillGoodsId);
        DtsSeckillBatch seckillBatch = seckillCache.getSeckillBatch(seckillGoods.getBatchId());

        // 判断活动是否开始且当前时间在秒杀批次内
        LocalTime nowTime = LocalTime.now();
        LocalDate today = LocalDate.now();

        if (seckillGoods.getStartDay().isBefore(today)
                && seckillGoods.getEndDay().isAfter(today)
                && seckillBatch.getStartTime().isBefore(nowTime)
                && seckillBatch.getEndTime().isAfter(nowTime)) {
            logger.warn("秒杀商品 seckillGoodsId: {}, 活动进行中！", seckillGoodsId);
            return true;
        } else {
            return false;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Object delete(DtsSeckillGoods dtsSeckillGoods) {
        dtsSeckillGoodsMapper.logicalDeleteByPrimaryKey(dtsSeckillGoods.getId());
        // 如果缓存中存在该商品的数据，清理缓存数据，减少缓存数据
        seckillCache.clearSeckillGoodsData(dtsSeckillGoods.getId());
        return ResponseUtils.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    public Object create(SeckillGoodsAllinone seckillGoodsAllinone) {
        DtsSeckillGoods seckillGoods =  seckillGoodsAllinone.getSeckillGoods();
        DtsGoodsProduct[] products = seckillGoodsAllinone.getProducts();

        DtsGoods dtsGoods = findDtsGoodsById(seckillGoods.getGoodsId());
        Integer leftNumber = 0;
        BigDecimal minSeckillPrice = null;
        List<Integer> productIds = new ArrayList<>();
        for (DtsGoodsProduct product : products) {
            BigDecimal seckillPrice = product.getSeckillPrice();
            if (seckillPrice == null || seckillPrice.compareTo(new BigDecimal(0)) <= 0) {
                continue;
            }
            DtsGoodsProduct seckillProduct = new DtsGoodsProduct();
            Integer seckillNumber = product.getSeckillNumber();
            minSeckillPrice = minSeckillPrice == null ? seckillPrice : switchLesserPrice(minSeckillPrice, seckillPrice);

            seckillProduct.setId(product.getId());
            seckillProduct.setSeckillNumber(seckillNumber);
            seckillProduct.setSeckillPrice(seckillPrice);
            if (seckillNumber.intValue() > 0) {
                // 设置了商品库存，则把货品ID存储到秒杀商品的货品集合
                productIds.add(product.getId());
            }
            seckillCache.setSeckilledProductLeftNum(product.getId(), seckillNumber, seckillGoods.getEndDay());

            // 秒杀货品仅需修改秒杀库存和秒杀价格，其他参数值不做调整
            dtsGoodsProductMapper.updateByPrimaryKeySelective(seckillProduct);
            leftNumber += seckillNumber;
        }

        seckillGoods.setLeftNumber(leftNumber);
        seckillGoods.setTotalNumber(leftNumber);
        seckillGoods.setSeckillPrice(minSeckillPrice);
        seckillGoods.setAddTime(LocalDateTime.now());
        seckillGoods.setUpdateTime(LocalDateTime.now());
        seckillGoods.setGoodsName(dtsGoods.getName());
        seckillGoods.setRetailPrice(dtsGoods.getRetailPrice());
        seckillGoods.setPicUrl(dtsGoods.getPicUrl());
        seckillGoods.setBrief(dtsGoods.getBrief());
        dtsSeckillGoodsMapper.insertSelective(seckillGoods);

        // 修改秒杀商品在缓存中的数据,注意，一旦修改秒杀商品，则以修改后的为准
        seckillCache.loadSeckillGoodsToRedis(seckillGoods);
        seckillCache.setGoodsProductIds(seckillGoods.getId(), productIds, seckillGoods.getEndDay());

        return ResponseUtils.ok();
    }

    private BigDecimal switchLesserPrice(BigDecimal minSeckillPrice, BigDecimal seckillPrice) {
        return  minSeckillPrice.compareTo(seckillPrice) > 0 ? seckillPrice : minSeckillPrice;
    }

    /**
     * 判断某个商品是否配置了未结束的秒杀
     * @param goodsId
     * @return
     */
    public boolean existSeckillGoods(Integer goodsId) {
        DtsSeckillGoodsExample goodsExample = new DtsSeckillGoodsExample();
        goodsExample.or().andGoodsIdEqualTo(goodsId).andDeletedEqualTo(false);
        return dtsSeckillGoodsMapper.countByExample(goodsExample) > 0;
    }

    /**
     * 验证秒杀配置的基本参数
     * @param seckillGoods
     * @return
     */
    public Object validateSeckillGoodsConf(SeckillGoodsAllinone seckillGoods) {
        SeckillGoodsVo goods = seckillGoods.getSeckillGoods();
        if (goods == null) {
            return ResponseUtils.badArgument();
        }
        Integer goodsId = goods.getGoodsId();
        if (Objects.isNull(goodsId)) {
            return ResponseUtils.badArgument();
        }
        Integer batchId = goods.getBatchId();
        if (Objects.isNull(batchId)) {
            return ResponseUtils.badArgument();
        }

        List<LocalDate> seckillTime = goods.getSeckillTime();
        if (Objects.isNull(seckillTime)) {
            return ResponseUtils.badArgument();
        }

        if (seckillTime.size() != 2) {
            return ResponseUtils.badArgument();
        }

        LocalDate endDay = seckillTime.get(1);
        LocalDate startDay = seckillTime.get(0);

        seckillGoods.getSeckillGoods().setStartDay(startDay);
        seckillGoods.getSeckillGoods().setEndDay(endDay);

        if (endDay == null || startDay == null || endDay.isBefore(startDay)) {
            return ResponseUtils.badArgumentValue();
        }

        Boolean repeatSeckill = goods.getRepeatSeckill();
        if (Objects.isNull(repeatSeckill)) {
            return ResponseUtils.badArgument();
        }

        DtsGoodsProduct[] products = seckillGoods.getProducts();
        if (products == null || products.length == 0) {
            return ResponseUtils.badArgumentValue();
        }
        return null;
    }

    /**
     * 获取某个商品信息,包含完整信息
     *
     * @param goodsId
     * @return
     */
    public DtsGoods findDtsGoodsById(Integer goodsId) {
        return goodsMapper.selectByPrimaryKey(goodsId);
    }

    public Object detail(Integer id) {
        DtsSeckillGoods dbGoods = dtsSeckillGoodsMapper.selectByPrimaryKey(id);
        SeckillGoodsVo goodsVo = new SeckillGoodsVo();
        BeanUtils.copyProperties(dbGoods, goodsVo);

        List<LocalDate> seckillTime = new ArrayList<>();
        seckillTime.add(dbGoods.getStartDay());
        seckillTime.add(dbGoods.getEndDay());
        goodsVo.setSeckillTime(seckillTime);

        List<DtsGoodsProduct> products = productService.querySeckillByGid(dbGoods.getGoodsId());
        Map<String, Object> data = new HashMap<>();
        data.put("goods", goodsVo);
        data.put("products", products);
        return ResponseUtils.ok(data);
    }

    @Transactional(rollbackFor = Exception.class)
    public Object update(SeckillGoodsAllinone seckillGoodsAllinone) {
        DtsSeckillGoods seckillGoods = seckillGoodsAllinone.getSeckillGoods();
        DtsGoodsProduct[] products = seckillGoodsAllinone.getProducts();

        Integer leftNumber = 0;
        BigDecimal minSeckillPrice = null;
        List<Integer> productIds = new ArrayList<>();
        for (DtsGoodsProduct product : products) {
            DtsGoodsProduct seckillProduct = new DtsGoodsProduct();
            Integer seckillNumber = product.getSeckillNumber();
            BigDecimal seckillPrice = product.getSeckillPrice();
            minSeckillPrice = minSeckillPrice == null ? seckillPrice : switchLesserPrice(minSeckillPrice, seckillPrice);

            seckillProduct.setId(product.getId());
            seckillProduct.setSeckillNumber(seckillNumber);
            seckillProduct.setSeckillPrice(seckillPrice);
            if (seckillNumber.intValue() > 0) {
                // 设置了商品库存，则把货品ID存储到秒杀商品的货品集合
                productIds.add(product.getId());
            }
            seckillCache.setSeckilledProductLeftNum(product.getId(), seckillNumber, seckillGoods.getEndDay());

            // 秒杀货品仅需修改秒杀库存和秒杀价格，其他参数值不做调整
            dtsGoodsProductMapper.updateByPrimaryKeySelective(seckillProduct);
            leftNumber += seckillNumber;
        }
        seckillGoods.setLeftNumber(leftNumber);
        seckillGoods.setTotalNumber(leftNumber);
        seckillGoods.setSeckillPrice(minSeckillPrice);
        seckillGoods.setUpdateTime(LocalDateTime.now());
        dtsSeckillGoodsMapper.updateByPrimaryKeySelective(seckillGoods);

        // 修改秒杀商品在缓存中的数据,注意，一旦修改秒杀商品，则以修改后的为准
        seckillCache.loadSeckillGoodsToRedis(seckillGoods);
        seckillCache.setGoodsProductIds(seckillGoods.getId(), productIds, seckillGoods.getEndDay());

        return ResponseUtils.ok();
    }


    /**
     * 秒杀商品列表
     *
     * @param seckillId 秒杀商品ID
     * @return 数据
     */
    public SeckillGoodsVo qrySeckillGoodInfoByBatchId(int seckillId) {
        Map<String, Object> map = new HashMap<>();
        map.put("seckillId", seckillId);
        SeckillGoodsVo seckillGoods = null;
        List<SeckillGoodsVo> seckillGoodsList = dtsSeckillGoodsMapperEx.qryBatchSeckillGoodsByBatchId(map);
        if (CollectionUtils.isNotEmpty(seckillGoodsList)) {
            seckillGoods = seckillGoodsList.get(0);
        }
        return seckillGoods;
    }

    /**
     * 结束秒杀，设置db数据商品秒杀结束和秒杀库存剩余结束，且设置缓存中的剩余数为0
     * @param seckillGoods
     * @return
     */
    public Object finish(DtsSeckillGoods seckillGoods) {
        DtsGoodsProductExample example = new DtsGoodsProductExample();
        example.createCriteria().andGoodsIdEqualTo(seckillGoods.getGoodsId()).andSeckillPriceGreaterThan(BigDecimal.ZERO);
        // 秒杀货品
        List<DtsGoodsProduct> dtsGoodsProducts = dtsGoodsProductMapper.selectByExample(example);
        // 将每个货品的数量清零
        dtsGoodsProducts.forEach(item -> {
            DtsGoodsProduct product = new DtsGoodsProduct();
            product.setId(item.getId());
            product.setSeckillNumber(0);// 将数据清零
            /**
             * 设置缓存货品的剩余数量为0，且有效期当天过后清理（结束的目的是马上结束不可继续秒杀）
             */
            seckillCache.setSeckilledProductLeftNum(item.getId(), 0, LocalDate.now());
            dtsGoodsProductMapper.updateByPrimaryKeySelective(product);
        });

        // 设置秒杀商品结束时间
        DtsSeckillGoods dtsSeckillGoods = new DtsSeckillGoods();
        dtsSeckillGoods.setId(seckillGoods.getId());
        dtsSeckillGoods.setFinishTime(LocalDateTime.now());
        dtsSeckillGoods.setUpdateTime(LocalDateTime.now());
        dtsSeckillGoods.setLeftNumber(0);
        dtsSeckillGoodsMapper.updateByPrimaryKeySelective(dtsSeckillGoods);

        // 如果缓存中存在该商品的数据，清理缓存数据，减少缓存数据
        seckillCache.clearSeckillGoodsData(seckillGoods.getId());

        return ResponseUtils.ok();
    }
}
